package com.heima.article.service;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.article.mapper.ApArticleConfigMapper;
import com.heima.article.mapper.ApArticleContentMapper;
import com.heima.article.mapper.ApArticleMapper;
import com.heima.article.thread.AppThreadLocalUtil;
import com.heima.common.cache.CacheService;
import com.heima.common.constants.ArticleConstants;
import com.heima.common.constants.BehaviorConstants;
import com.heima.common.freemarker.FreemarkerGenerator;
import com.heima.file.MinIoTemplate;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.article.dtos.ArticleHomeDto;
import com.heima.model.article.dtos.ArticleInfoDto;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.article.pojos.ApArticleConfig;
import com.heima.model.article.pojos.ApArticleContent;
import com.heima.model.article.vos.HotArticleVo;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.search.vos.SearchArticleVo;
import com.heima.model.user.pojos.ApUser;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.User;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class ApArticleServiceImpl extends ServiceImpl<ApArticleMapper, ApArticle> implements ApArticleService {
    @Autowired
    private ApArticleMapper apArticleMapper;

    @Override
    public ResponseResult load(ArticleHomeDto dto) {
        //minBehotTime = 2063
        //publish_time < minBehotTime
        List<ApArticle> apArticles = apArticleMapper.loadArticle(dto, 1);
        return ResponseResult.okResult(apArticles);
    }

    @Override
    public ResponseResult loadmore(ArticleHomeDto dto) {
        //publish_time < minBehotTime
        List<ApArticle> apArticles = apArticleMapper.loadArticle(dto, 1);
        return ResponseResult.okResult(apArticles);
    }

    @Override
    public ResponseResult loadnew(ArticleHomeDto dto) {
        //publish_time > minBehotTime
        List<ApArticle> apArticles = apArticleMapper.loadArticle(dto, 2);
        return ResponseResult.okResult(apArticles);
    }

    @Autowired
    private ApArticleContentMapper apArticleContentMapper;
    @Autowired
    private FreemarkerGenerator freemarkerGenerator;
    @Autowired
    private ApArticleConfigMapper apArticleConfigMapper;
    @Autowired
    private MinIoTemplate minIoTemplate;


    @Override
    public void generate(Long articleId) {
        //1.查询ApArticleContent表，获取content信息
        LambdaQueryWrapper<ApArticleContent> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ApArticleContent::getArticleId, articleId);
        ApArticleContent apArticleContent = apArticleContentMapper.selectOne(wrapper);
        if (apArticleContent == null) {
            log.warn("文章内容不存在");
            return;
        }
        //2.创建一个集合Map，把上一步content数据赋值到map的content字段上
        Map<String, Object> map = new HashMap<>(1);
        map.put("content", JSON.parseArray(apArticleContent.getContent()));
        //3.调用freemarker插件，生成HTML页面
        InputStream inputStream = freemarkerGenerator.generate("article.ftl", map);
        //4.调用minio插件，上传HTML页面
        String url = minIoTemplate.uploadFile("", articleId + ".html", inputStream, "html");

        ApArticle apArticle = apArticleMapper.selectById(articleId);
        if (apArticle == null) {
            log.warn("文章为空");
            return;
        }
        apArticle.setStaticUrl(url);
        //5.更新ApArticle,修改里面的static_url字段
        apArticleMapper.updateById(apArticle);
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public ResponseResult saveArticle(ArticleDto dto) {
        //1.dto判空
        if (dto == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        Long id = dto.getId();
        String content = dto.getContent();

        //组装article表数据
        ApArticle apArticle = new ApArticle();
        BeanUtils.copyProperties(dto, apArticle);
        //判断dto里面是否有id的存在
        if (id == null) {
            //2.新增流程
            //2.1 新增article表
            int insertResult = apArticleMapper.insert(apArticle);
            if (insertResult < 1) {
                return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, "文章新增失败");
            }
            //2.2 新增article_config表
            ApArticleConfig config = new ApArticleConfig();
            config.setIsDown(false);
            config.setIsDelete(false);
            config.setIsForward(true);
            config.setIsComment(true);
            config.setArticleId(apArticle.getId());
            int configInsertResult = apArticleConfigMapper.insert(config);
            if (configInsertResult < 1) {
                log.warn("文章配置表插入失败");
                throw new RuntimeException("文章配置表插入失败");
            }

            //2.3 新增article_content表
            ApArticleContent apArticleContent = new ApArticleContent();
            apArticleContent.setContent(content);
            apArticleContent.setArticleId(apArticle.getId());
            int contentInsertResult = apArticleContentMapper.insert(apArticleContent);
            if (contentInsertResult < 1) {
                log.warn("文章内容表插入失败");
                throw new RuntimeException("文章内容表插入失败");
            }
            return ResponseResult.okResult(apArticle.getId());
        } else {
            //3.修改流程
            //3.1 修改article表
            int updateResult = apArticleMapper.updateById(apArticle);
            if (updateResult < 1) {
                return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, "文章修改失败");
            }
            //3.2 修改article_content表
            ApArticleContent contentUpdate = new ApArticleContent();
            contentUpdate.setContent(content);

            LambdaQueryWrapper<ApArticleContent> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(ApArticleContent::getArticleId, id);
            int contentUpdateResult = apArticleContentMapper.update(contentUpdate, wrapper);

            if (contentUpdateResult < 1) {
                log.warn("文章内容表修改失败");
                throw new RuntimeException("文章内容表修改失败");
            }
            indexUpdate(apArticle, content);
            return ResponseResult.okResult(id);
        }
    }

    @Autowired
    private CacheService cacheService;

    @Override
    public ResponseResult loadArticleBehavior(ArticleInfoDto dto) {
        if (dto == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        //初始化行为
        boolean islike = false;
        boolean isunlike = false;
        boolean iscollection = false;
        boolean isfollow = false;
        //登录校验
        ApUser user = AppThreadLocalUtil.getUser();
        Integer userId = user.getId();
        Long articleId = dto.getArticleId();
        Integer authorId = dto.getAuthorId();
        if (user != null) {
            //点赞行为
            String likeBehavior = (String) cacheService.hGet(BehaviorConstants.LIKE_BEHAVIOR + articleId, userId.toString());
            if (StringUtils.isNotBlank(likeBehavior)) {
                islike = true;
            }
            //不喜欢行为
            String isunlikeBehavior = (String) cacheService.hGet(BehaviorConstants.UN_LIKE_BEHAVIOR + articleId, userId.toString());
            if (StringUtils.isNotBlank(isunlikeBehavior)) {
                isunlike = true;
            }
            //收藏行为
            String iscollectionBehavior = (String) cacheService.hGet(BehaviorConstants.COLLECTION_BEHAVIOR + articleId, userId.toString());
            if (StringUtils.isNotBlank(iscollectionBehavior)) {
                iscollection = true;
            }
            //关注行为
            Double score = cacheService.zScore(BehaviorConstants.APUSER_FOLLOW_RELATION + articleId, userId.toString());
            if (score != null){
                isfollow = true;
            }
        }
        //将所有行为包装到map中返回
        Map<String,Object> resultMap = new HashMap<>();
        resultMap.put("islike",islike);
        resultMap.put("isunlike",isunlike);
        resultMap.put("iscollection",iscollection);
        resultMap.put("isfollow",isfollow);
        return ResponseResult.okResult(resultMap);
    }

    @Override
    public ResponseResult load2(ArticleHomeDto dto, boolean firstPage) {
        //首页判断
        if(firstPage){
            String jsonStr = cacheService.get(ArticleConstants.HOT_ARTICLE_FIRST_PAGE + dto.getTag());
            if(StringUtils.isNotBlank(jsonStr)){
                List<HotArticleVo> hotArticleVoList = JSON.parseArray(jsonStr, HotArticleVo.class);
                ResponseResult responseResult = ResponseResult.okResult(hotArticleVoList);
                return responseResult;
            }
        }
        return load(dto);
    }

    @Autowired
    private KafkaTemplate<String, Object> kafkaTemplate;

    private void indexUpdate(ApArticle apArticle, String content) {
        //入参判空
        if (apArticle == null) {
            log.warn("入参不能为空");
            return;
        }
        SearchArticleVo vo = new SearchArticleVo();
        //将apArticle赋值到vo上去
        BeanUtils.copyProperties(apArticle, vo);
        //vo拥有了所有的内容数据
        vo.setContent(content);
        //将vo转化成string字符串
        String s = JSON.toJSONString(vo);
        //kafka发送数据到"es.index.update"
        kafkaTemplate.send("es.index.update", s);
    }
}
